package com.diytomcat.catalina;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.diytomcat.Bootstrap;
import com.diytomcat.http.Request;
import com.diytomcat.http.Response;
import com.diytomcat.util.Constant;
import com.diytomcat.util.ThreadPoolUtil;
import com.diytomcat.util.WebXMLUtil;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;

public class Server {

	private Service service;

	public Server() {
		this.service = new Service(this);
	}

	public void start() {
		logJVM();
		inint();
	}

	private void inint() {
		int port = 18080;

		try {
			@SuppressWarnings("resource")
			ServerSocket ss = new ServerSocket(port);

			// 持续获取数据
			while (true) {

				Socket s = ss.accept();
				Runnable r = new Runnable() {

					@Override
					public void run() {
						try {

							Request request = new Request(s, service);
							Context context = request.getContext();
							System.out.println("浏览器的输入信息： \\r\\n" + request.getRequestString());

							Response response = new Response();
							String uri = request.getUri();
							if (null == uri)
								return;
							System.out.println("uri" + uri);

							if ("/500.html".equals(uri)) {
								throw new Exception("this is a deliberately created exception");
							}
							//当 uri 等于 "/" 的时候， uri 就修改成欢迎文件，后面就当作普通文件来处理了
							if ("/".equals(uri)) {
								uri = WebXMLUtil.getWelcomeFile(context);
							} else {

								String fileName = StrUtil.removePrefix(uri, "/");
								if ("timeConsume.html".equals(fileName)) {
									Thread.sleep(1000);
								}
								File file = new File(context.getDocBase(), fileName);
								if (file.exists()) {
									String fileContent = FileUtil.readUtf8String(file);
									response.getWriter().println(fileContent);

									if ("timeConsume.html".equals(fileName)) {
										Thread.sleep(1000);
									}
								} else {
									handle404(s, uri);
									return;
								}
							}

							handle200(s, response);
						} catch (Exception e) {
							Logger.getLogger(Bootstrap.class).error(e);
							e.printStackTrace();
						} finally {
							try {
								if (!s.isClosed())
									s.close();
							} catch (Exception e2) {
								e2.printStackTrace();
							}
						}
					}
				};
				ThreadPoolUtil.run(r);
			}
		} catch (Exception e) {
			Logger.getLogger(Bootstrap.class).error(e);
			e.printStackTrace();
		}
	}

	/**
	 * @description
	 * @2020年6月8日下午1:35:18
	 * @param s
	 * @param response
	 * @throws IOException
	 */
	private static void handle200(Socket s, Response response) throws IOException {
		// text/html
		String contentType = response.getContentType();
		String headText = Constant.response_head_202;
		headText = StrUtil.format(headText, contentType);

		byte[] head = headText.getBytes();
		byte[] body = response.getBody();

		byte[] responseBytes = new byte[head.length + body.length];
		/*
		 * 数组拷贝 param head-源数组 param 0-源数组开始位置 param responseBytes-目标数组 param 0-目标数组开始位置
		 * param head.length-拷贝数组长度
		 */
		System.arraycopy(head, 0, responseBytes, 0, head.length);
		System.arraycopy(body, 0, responseBytes, head.length, body.length);

		OutputStream os = s.getOutputStream();
		os.write(responseBytes);
		s.close();
	}

	/**
	 * description: 404 页面输出
	 * 
	 * @param s
	 * @param uri
	 * @throws IOException
	 */
	protected void handle404(Socket s, String uri) throws IOException {
		OutputStream os = s.getOutputStream();
		String responseText = StrUtil.format(Constant.textFormat_404, uri, uri);
		responseText = Constant.response_head_404 + responseText;
		byte[] responseByte = responseText.getBytes("utf-8");
		os.write(responseByte);
	}

	protected void handle500(Socket s, Exception e) {
		try {
			OutputStream os = s.getOutputStream();
			StackTraceElement[] stes = e.getStackTrace();
			StringBuffer sb = new StringBuffer();
			sb.append(e.toString());
			sb.append("\r\n");

			for (StackTraceElement ste : stes) {
				sb.append("\t");
				sb.append(ste.toString());
				sb.append("\r\n");
			}
			String msg = e.getMessage();
			if (null != msg && msg.length() > 20)
				msg = msg.substring(0, 19);

			String text = StrUtil.format(Constant.textFormat_500, msg.toString(), sb.toString());
			text = Constant.response_head_500 + text;
			byte[] responseBytes = text.getBytes("utf-8");
			os.write(responseBytes);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * @description 日志处理
	 * @2020年6月9日上午10:41:25
	 */
	private static void logJVM() {
		Map<String, String> infos = new LinkedHashMap<>();
		infos.put("Server Version", "DiyTomcat/1.0.1");
		infos.put("Server Buid", "2020-06-07 10:00:00");
		infos.put("Server Number", "1.0.1");
		// 操作系统名称
		infos.put("OS Name\t", SystemUtil.get("os.name"));
		infos.put("OS Version", SystemUtil.get("os.version"));
		infos.put("Architecture", SystemUtil.get("os.arch"));
		infos.put("Java Home", SystemUtil.get("java.home"));
		infos.put("JVM Version", SystemUtil.get("java.runtime.version"));
		infos.put("JVM Vendor", SystemUtil.get("java.vm.specification.vendor"));

		Set<String> keys = infos.keySet();
		for (String key : keys) {
			Logger logger = Logger.getLogger(Bootstrap.class);
			logger.info(key + ":\t\t" + infos.get(key));
		}
	}
}
